#ifndef M_BLINNPHONG
#define M_BLINNPHONG
#include"BxDF.h"
class BlinnPhongReflection : public BxDF
{
#define DEFAULT__BLINNPHONG_N 16
#define DEFAULT_DIVIDED 0
private:
	int n; //coefficient
	bool divide_by_NdotL;
	Spectrum ks;
public:
	BlinnPhongReflection(Spectrum &ks,int _n= DEFAULT__BLINNPHONG_N,int _divided_by_NL= DEFAULT_DIVIDED, int flags=BxDFType(BSDF_GLOSSY | BSDF_REFLECTION)):
		ks(ks),n(_n), divide_by_NdotL(_divided_by_NL), BxDF(BxDFType(flags)) {}
	virtual Spectrum f(P3 &light, P3 &view)
	{

		P3 H = (light+view).norm();
		if (H.z < 0) return 0.;
		//P3 H = H.z < 0 ? -H : H;
		// specular
		Float NH = H.z;
		Float val = pow(NH, n)  * (n+2)*Inv2Pi;
		if (divide_by_NdotL&&light.z>eps)
			val = val / light.z;
		
		return ks*val;
	}

	virtual P3 ImportanceSample(P3& light, Float* rands, Float* pdf)
	{
		Float cosTheta = pow(rands[0], 1.0f / (n + 1));
		if (light.z < 0) cosTheta = -cosTheta;
		Float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
		Float phi = 2 * Pi * rands[1];
		P3 H(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);

		P3 view = (-light.reflect(H)).norm();
		*pdf = getPdf(light, view);
		return view;
	}
	virtual Float getPdf(P3& light, P3& view)
	{
		if (light.z * view.z <= 0) //not in the same hemisphere
			return 0;
		P3 H = (light + view).norm();
		Float vh = view.dot(H);
		return (n+1)*Inv2Pi * pow(H.z, n) / (4 * vh);
	}
};
#endif // !M_BLINNPHONG

